package org.finesys.common.doc.config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.finesys.common.doc.properties.DocProperties;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.NonNull;

import cn.hutool.core.text.StrPool;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.Scopes;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;

@AutoConfiguration
@EnableConfigurationProperties(DocProperties.class)
@RequiredArgsConstructor
public class DocAutoConfiguration implements ApplicationContextAware {


    private final DocProperties docProperties;
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Bean
    @ConditionalOnProperty(prefix = "fine.common.doc", value = "enabled", havingValue = "true", matchIfMissing = true)
    public OpenAPI springShopOpenAPI() {
        String[] beanNamesForType = applicationContext.getBeanNamesForType(ServiceInstance.class);
        if (beanNamesForType.length == 0) {
            return null;
        }
        ServiceInstance serviceInstance = applicationContext.getBean(ServiceInstance.class);
        // 获取服务实例信息
        String serviceId = serviceInstance.getServiceId();
        // 获取服务路由前缀
        List<Server> servers = new ArrayList<>();
        servers.add(new Server().url(docProperties.getUrl() + StrPool.SLASH + serviceId.substring(serviceId.lastIndexOf("-") + 1)));

        OpenAPI openAPI = new OpenAPI().servers(servers).info(new Info().title(docProperties.getTitle()).description(docProperties.getDescription()).version(docProperties.getVersion()).contact(new Contact().name(docProperties.getAuthor())));
        //oauth2安全认证
        if (docProperties.isSecurityEnabled()) {
            openAPI.schemaRequirement(HttpHeaders.AUTHORIZATION, securityScheme(docProperties));
        }

        return openAPI;
    }

    /**
     * oauth2安全认证
     */
    private SecurityScheme securityScheme(DocProperties docProperties) {
        //组装获取token信息
        OAuthFlow oAuthFlow = new OAuthFlow();
        oAuthFlow.setTokenUrl(docProperties.getTokenUrl());
        Scopes scopes = new Scopes();
        Arrays.stream(docProperties.getScope().split(",")).forEach(scope -> {
            scopes.addString(scope, scope);
        });
        oAuthFlow.setScopes(scopes);
        //放置密码
        OAuthFlows oAuthFlows = new OAuthFlows();
        oAuthFlows.setPassword(oAuthFlow);
        //返回安全认证信息
        SecurityScheme securityScheme = new SecurityScheme();
        securityScheme.setFlows(oAuthFlows);
        securityScheme.setType(SecurityScheme.Type.OAUTH2);
        return securityScheme;
    }

}
